home *** CD-ROM | disk | FTP | other *** search
/ Komputer for Alle 2001 #11 / CD 11 (Black) - 2001.iso / FAVORG / FAVO_SRC.ZIP / MultiselTreeCtrl.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-27  |  8.0 KB  |  339 lines

  1. // FAVORG Version 1.1
  2. // Copyright (c) 2000 Ziff Davis Media, Inc.
  3. // All rights reserved.
  4. // First Published in PC Magazine, US Edition, November 7, 2000.
  5. // Programmer: Patrick Philippot
  6.  
  7. #include "stdafx.h"
  8. #include "MultiselTreeCtrl.h"
  9.  
  10. #ifdef _DEBUG
  11. #define new DEBUG_NEW
  12. #undef THIS_FILE
  13. static char THIS_FILE[] = __FILE__;
  14. #endif
  15.  
  16. /////////////////////////////////////////////////////////////////////////////
  17. // CMultiselTreeCtrl
  18. //
  19. // This code is a major rework of classes found at www.codeguru.com
  20. // It partially implements multiple selection in the standard
  21. // Windows tree control.
  22.  
  23. CMultiselTreeCtrl::CMultiselTreeCtrl()
  24. {
  25.     m_hItemFirstSel = NULL;
  26. }
  27.  
  28. CMultiselTreeCtrl::~CMultiselTreeCtrl()
  29. {
  30. }
  31.  
  32. BEGIN_MESSAGE_MAP(CMultiselTreeCtrl, CTreeCtrl)
  33.     //{{AFX_MSG_MAP(CMultiselTreeCtrl)
  34.     ON_WM_LBUTTONDOWN()
  35.     ON_WM_KEYDOWN()
  36.     ON_WM_KILLFOCUS()
  37.     ON_WM_SETFOCUS()
  38.     ON_WM_RBUTTONDOWN()
  39.     //}}AFX_MSG_MAP
  40. END_MESSAGE_MAP()
  41.  
  42. /////////////////////////////////////////////////////////////////////////////
  43. // CMultiselTreeCtrl message handlers
  44.  
  45. void CMultiselTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
  46. {
  47.     UINT flags;
  48.     HTREEITEM m_hSelectedItem = HitTest(point, &flags);
  49.  
  50.     if ((flags & TVHT_ONITEM) == 0)
  51.         m_hSelectedItem = NULL;
  52.  
  53.     if (m_hSelectedItem == NULL)    
  54.     {
  55.         //UpdateSelectedItems();
  56.         ClearSelection(TRUE);
  57.         CTreeCtrl::OnLButtonDown(nFlags, point);
  58.         return;
  59.     }
  60.  
  61.     BOOL bAlreadySelected = (GetItemState(m_hSelectedItem, TVIS_SELECTED) & TVIS_SELECTED) != 0;
  62.  
  63.     if ((!bAlreadySelected) && (flags & TVHT_ONITEM))
  64.     {
  65.         if (nFlags & MK_CONTROL)
  66.         {
  67.             //CTRL Key is set so select multiple items.
  68.             if (!m_SelItemList.IsEmpty()) //there are few items already..
  69.             {
  70.                 //Verify current item is a sibling of existing item in list..
  71.                 if (!IsSibling((HTREEITEM)m_SelItemList.GetTail(), m_hSelectedItem))
  72.                     return;
  73.             }
  74.  
  75.             m_SelItemList.AddTail(m_hSelectedItem);
  76.             // Toggle selection state
  77.             UINT uNewSelState =  GetItemState(m_hSelectedItem, 
  78.                                               TVIS_SELECTED) & TVIS_SELECTED ? 0 : TVIS_SELECTED;
  79.  
  80.             // Get old selected (focus) item and state
  81.             HTREEITEM hItemOld = GetSelectedItem();
  82.             UINT uOldSelState  = hItemOld ? GetItemState(hItemOld, TVIS_SELECTED) : 0;
  83.  
  84.             // Select new item
  85.             if (GetSelectedItem() == m_hSelectedItem)
  86.                 SelectItem(NULL);
  87.             
  88.             CTreeCtrl::OnLButtonDown(nFlags, point);
  89.  
  90.             // Set proper selection (highlight) state for new item
  91.             SetItemState(m_hSelectedItem, uNewSelState, TVIS_SELECTED);
  92.  
  93.             // Restore state of old selected item
  94.             if (hItemOld && hItemOld != m_hSelectedItem)
  95.                 SetItemState(hItemOld, uOldSelState, TVIS_SELECTED);
  96.  
  97.             m_hItemFirstSel = NULL;
  98.  
  99.             return;
  100.         }
  101.         else if (nFlags & MK_SHIFT)
  102.         {
  103.             //SHIFT Key is set so select multiple items.
  104.             UINT flag;
  105.             HTREEITEM hItem = HitTest(point, &flag);
  106.  
  107.             // Initialize the reference item if this is the first shift selection
  108.             if (!m_hItemFirstSel)
  109.                 m_hItemFirstSel = GetSelectedItem();
  110.  
  111.             // Select new item
  112.             if (GetSelectedItem() == hItem)
  113.                 SelectItem(NULL);            // to prevent edit
  114.  
  115.             CTreeCtrl::OnLButtonDown(nFlags, point);
  116.  
  117.             if (m_hItemFirstSel)
  118.             {
  119.                 SelectItems(m_hItemFirstSel, hItem);
  120.                 return;
  121.             }
  122.         }
  123.         else if (nFlags & MK_SHIFT & MK_CONTROL)
  124.         {
  125.         }
  126.         else
  127.         {
  128.             ClearSelection(FALSE);
  129.             m_hItemFirstSel = NULL;
  130.             m_SelItemList.AddTail(m_hSelectedItem);
  131.  
  132.             CTreeCtrl::OnLButtonDown(nFlags, point);
  133.         }
  134.     }
  135.     else if (bAlreadySelected && (nFlags & MK_CONTROL))
  136.     {
  137.         m_SelItemList.RemoveAt(m_SelItemList.Find(m_hSelectedItem));
  138.         SetItemState(m_hSelectedItem, 0, TVIS_SELECTED);
  139.     }
  140.     else if (bAlreadySelected)
  141.     {
  142.         if (m_SelItemList.GetCount() > 1)
  143.         {
  144.             ClearSelection(FALSE);
  145.             SelectItem(NULL);
  146.             m_SelItemList.AddTail(m_hSelectedItem);
  147.             SelectItem(m_hSelectedItem);
  148.         }
  149.  
  150.         CTreeCtrl::OnLButtonDown(nFlags, point);
  151.         UpdateSelectedItems();
  152.     }
  153.     else
  154.     {
  155.         CTreeCtrl::OnLButtonDown(nFlags, point);
  156.         UpdateSelectedItems();
  157.     }
  158. }
  159.  
  160. void CMultiselTreeCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  161. {
  162.     if (nChar == VK_F2)
  163.     {
  164.         HTREEITEM hItem = GetSelectedItem();
  165.         if (hItem != NULL)
  166.             EditLabel(hItem);
  167.         
  168.         return;
  169.     }
  170.  
  171.     if ((nChar == VK_UP || nChar == VK_DOWN) && (GetKeyState(VK_SHIFT) & 0x8000))
  172.     {
  173.         // Initialize the reference item if this is the first shift selection
  174.         if (!m_hItemFirstSel)
  175.         {
  176.             ClearSelection(FALSE);
  177.             m_hItemFirstSel = GetSelectedItem();
  178.             m_SelItemList.AddTail(m_hItemFirstSel);
  179.         }
  180.  
  181.         // Find which item is currently selected
  182.         HTREEITEM    hItemPrevSel = GetSelectedItem();
  183.         HTREEITEM    hItemNext;
  184.         BOOL        bIsDir = GetItemData(m_hItemFirstSel);
  185.  
  186.         if (nChar==VK_UP)
  187.             hItemNext = GetPrevVisibleItem(hItemPrevSel);
  188.         else
  189.             hItemNext = GetNextVisibleItem(hItemPrevSel);
  190.  
  191.         if (hItemNext && (bIsDir == (BOOL) GetItemData(hItemNext)))
  192.         {
  193.             // Determine if we need to reselect previously selected item
  194.             BOOL bReselect = !(GetItemState(hItemNext, TVIS_SELECTED) & TVIS_SELECTED);
  195.  
  196.             // Select the next item - this will also deselect the previous item
  197.             m_SelItemList.AddTail(hItemNext);
  198.             SelectItem(hItemNext);
  199.  
  200.             // Reselect the previously selected item
  201.             if (bReselect)
  202.                 SetItemState(hItemPrevSel, TVIS_SELECTED, TVIS_SELECTED);
  203.         }
  204.         return;
  205.     }
  206.     else if (nChar == VK_UP || nChar == VK_DOWN)
  207.     {
  208.         m_hItemFirstSel = NULL;
  209.         ClearSelection(FALSE);
  210.  
  211.         CTreeCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
  212.  
  213.         HTREEITEM hItem = GetSelectedItem();
  214.  
  215.         if (hItem)
  216.             m_SelItemList.AddTail(hItem);
  217.  
  218.         return;
  219.     }
  220.     else if (nChar >= VK_SPACE)
  221.     {
  222.         m_hItemFirstSel = NULL;
  223.         ClearSelection(FALSE);
  224.     }    
  225.  
  226.     CTreeCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
  227. }
  228.  
  229. void CMultiselTreeCtrl::ClearSelection(BOOL bCleanTree)
  230. {
  231.     BOOL bMustUpdate = FALSE;
  232.  
  233.     if (!m_SelItemList.IsEmpty())
  234.     {
  235.         HTREEITEM hItem;
  236.  
  237.         POSITION pos = m_SelItemList.GetHeadPosition();
  238.  
  239.         while(pos != NULL)
  240.         {
  241.             hItem = m_SelItemList.GetNext(pos);
  242.             SetItemState(hItem, 0, TVIS_SELECTED);
  243.         }
  244.  
  245.         bMustUpdate =  m_SelItemList.GetCount() > 1;
  246.         m_SelItemList.RemoveAll();
  247.     }
  248.  
  249.     m_hItemFirstSel = NULL;
  250.     
  251.     if (bCleanTree)
  252.         SelectItem(NULL);
  253.  
  254.     if (bMustUpdate)
  255.         Invalidate();
  256. }
  257.  
  258. BOOL CMultiselTreeCtrl::IsSibling(HTREEITEM hItemFrom, HTREEITEM hItemTo)
  259. {
  260.     return (GetParentItem(hItemFrom) == GetParentItem(hItemTo));
  261. }
  262.  
  263. BOOL CMultiselTreeCtrl::SelectItems(HTREEITEM hItemFrom, HTREEITEM hItemTo)
  264. {
  265.     //If the given items aren't sibling do not multi-select
  266.     if (!IsSibling(hItemFrom, hItemTo))
  267.         return FALSE;
  268.  
  269.     ClearSelection(TRUE);
  270.  
  271.     HTREEITEM    hParentItem = GetParentItem(hItemFrom);
  272.     HTREEITEM    hChildItem = GetChildItem(hParentItem);
  273.     BOOL        bStarted = FALSE;
  274.     BOOL        bLastDone = FALSE;
  275.  
  276.     while ((hChildItem != NULL) && (!bStarted || (bStarted && !bLastDone)))
  277.     {
  278.         bLastDone = bStarted && ((hChildItem == hItemFrom) || (hChildItem == hItemTo));
  279.         bStarted = bStarted || (hChildItem == hItemFrom) || (hChildItem == hItemTo);
  280.  
  281.         if (bStarted)
  282.         {
  283.             SetItemState(hChildItem, TVIS_SELECTED, TVIS_SELECTED);
  284.             m_SelItemList.AddTail(hChildItem);
  285.         }
  286.  
  287.         if (!bLastDone)
  288.             hChildItem = GetNextItem(hChildItem, TVGN_NEXT);
  289.         else
  290.             // Useless but otherwise the dialog box will not get
  291.             // the selchanged notification
  292.             SelectItem(hChildItem);
  293.     }
  294.  
  295.     return TRUE;
  296. }
  297.  
  298. void CMultiselTreeCtrl::OnKillFocus(CWnd* pNewWnd) 
  299. {
  300.     CTreeCtrl::OnKillFocus(pNewWnd);
  301.     
  302.     UpdateSelectedItems();
  303. }
  304.  
  305. void CMultiselTreeCtrl::OnSetFocus(CWnd* pOldWnd) 
  306. {
  307.     CTreeCtrl::OnSetFocus(pOldWnd);
  308.     
  309.     UpdateSelectedItems();
  310. }
  311.  
  312. void CMultiselTreeCtrl::UpdateSelectedItems()
  313.     if (m_SelItemList.IsEmpty())
  314.     {
  315.         SelectItem(NULL);
  316.         return;
  317.     }
  318.  
  319.     HTREEITEM hCurItem = NULL;
  320.  
  321.     POSITION    pos = m_SelItemList.GetHeadPosition();
  322.     CRect        Rect;
  323.  
  324.     while (pos != NULL)
  325.     {
  326.         hCurItem = m_SelItemList.GetNext(pos);
  327.         GetItemRect(hCurItem, Rect, TRUE);
  328.         InvalidateRect(Rect); 
  329.     }
  330.  
  331.     UpdateWindow();
  332. }
  333.  
  334. void CMultiselTreeCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
  335. {
  336.     UpdateSelectedItems();    
  337. }
  338.